/*
 * SocketOption.cpp
 *
 *  Created on: 2012-12-7
 *      Author: yangentao@gmail.com
 */

#include "SocketOption.h"
#include <assert.h>
#include "SocketError.h"
#include <WinSock2.h>
namespace yet {

SocketOption::SocketOption(SOCKET sock) {
	assert(sock);
	assert(sock != INVALID_SOCKET);
	this->sock = sock;
}

SocketOption::~SocketOption() {
}
void SocketOption::setInt(int level, int optname, int value) {
	int n = setsockopt(sock, level, optname, (const char*) &value, sizeof(value));
	if (n != 0) {
		SocketError e;
		e.print();
		throw e;
	}
}
int SocketOption::getInt(int level, int optname) {
	int b = 0;
	int size = sizeof(b);
	int n = getsockopt(sock, level, optname, (char*) &b, &size);
	if (n != 0) {
		SocketError e;
		e.print();
		throw e;
	}
	return b;
}
void SocketOption::setSocketInt(int optname, int value) {
	setInt(SOL_SOCKET, optname, value);
}
int SocketOption::getSocketInt(int optname) {
	return getInt(SOL_SOCKET, optname);
}

void SocketOption::setTcpNoDelay(BOOL noDelay) {
	setInt(IPPROTO_TCP, TCP_NODELAY, noDelay);
}
BOOL SocketOption::isTcpNoDelay() {
	return getInt(IPPROTO_TCP, TCP_NODELAY);
}
LINGER SocketOption::getLinger() {
	LINGER ln = { 0 };
	int size = sizeof(ln);
	int n = getsockopt(sock, SOL_SOCKET, SO_LINGER, (char*) &ln, &size);
	if (n != 0) {
		SocketError e;
		e.print();
		throw e;
	}
	return ln;

}
void SocketOption::setLinger(BOOL on, short seconds) {
	assert(seconds >=0);
	if (on) {
		seconds = max(1, seconds);
	}
	LINGER ln;
	ln.l_onoff = on;
	ln.l_linger = seconds;
	int n = setsockopt(sock, SOL_SOCKET, SO_LINGER, (const char*) &ln, sizeof(ln));
	if (n != 0) {
		SocketError e;
		e.print();
		throw e;
	}
}
BOOL SocketOption::isBroadcastEnable() {
	return getSocketInt(SO_BROADCAST);
}
void SocketOption::setBroadcast(BOOL enable) {
	setSocketInt(SO_BROADCAST, enable);
}

//SO_SNDBUF
int SocketOption::getSendBufferSize() {
	return getSocketInt(SO_SNDBUF);
}
void SocketOption::setSendBufferSize(int size) {
	setSocketInt(SO_SNDBUF, size);
}
//SO_RCVBUF
int SocketOption::getReceiveBufferSize() {
	return getSocketInt(SO_RCVBUF);
}
void SocketOption::setReceiveBufferSize(int size) {
	setSocketInt(SO_RCVBUF, size);
}

int SocketOption::getMaxMsgSize() {
	return getInt(SOL_SOCKET, SO_MAX_MSG_SIZE);
}

BOOL SocketOption::isDebug() {
	return getSocketInt(SO_DEBUG);
}
void SocketOption::setDebug(BOOL dbg) {
	setSocketInt(SO_DEBUG, dbg);
}
BOOL SocketOption::isDontRoute() {
	return getSocketInt(SO_DONTROUTE);
}
void SocketOption::setDontRoute(BOOL dontRoute) {
	setSocketInt(SO_DONTROUTE, dontRoute);
}

BOOL SocketOption::isDontLinger() {
	return getSocketInt(SO_DONTLINGER);
}
void SocketOption::setDontLinger(BOOL dontLinger) {
	setSocketInt(SO_DONTLINGER, dontLinger);
}

BOOL SocketOption::isKeepAlive() {
	return getSocketInt(SO_KEEPALIVE);
}
void SocketOption::setKeepAlive(BOOL keepAlive) {
	setSocketInt(SO_KEEPALIVE, keepAlive);
}
BOOL SocketOption::isReuseAddr() {
	return getSocketInt(SO_REUSEADDR);
}
void SocketOption::setReuseAddr(BOOL reuse) {
	setSocketInt(SO_REUSEADDR, reuse);
}
BOOL SocketOption::isOOBInline() {
	return getSocketInt(SO_OOBINLINE);
}
void SocketOption::setOOBInline(BOOL inln) {
	setSocketInt(SO_OOBINLINE, inln);
}

BOOL SocketOption::isExclusiveAddrUse() {
	return getSocketInt(SO_EXCLUSIVEADDRUSE );
}
void SocketOption::setExclusiveAddrUse(BOOL exclusive) {
	setSocketInt(SO_EXCLUSIVEADDRUSE, exclusive);
}
//SOCKET SocketOption::getUpdateAcceptContext() {
//	return getSocketInt(SO_UPDATE_ACCEPT_CONTEXT);
//}
//void SocketOption::setUpdateAcceptContext(SOCKET listenSocket) {
//	setSocketInt(SO_UPDATE_ACCEPT_CONTEXT, listenSocket);
//}
BOOL SocketOption::isConditionalAccept() {
	return getSocketInt(SO_CONDITIONAL_ACCEPT);
}
void SocketOption::setConditionalAccept(BOOL condAccept) {
	setSocketInt(SO_CONDITIONAL_ACCEPT, condAccept);
}
} /* namespace yet */
